#pragma once

#include<iostream>
#include<string>
#include<cerrno>
#include<strings.h>
#include<cstring>
#include<functional>
#include<cstdlib>
#include<unistd.h> 
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>

namespace Server
{
    using namespace std;
    static const string defaultIp = "0.0.0.0";
    static const int gnum=1024;

    typedef function<void(int,string,uint16_t,string)> func_t;

    enum {USAGE_ERR = 1, SOCKET_ERR ,BIND_ERR ,OPEN_ERR};

    class udpServer
    {
    public:
        udpServer(const func_t& cb,const uint16_t &port,const string &ip=defaultIp)
        :_callback(cb),_port(port),_ip(ip),_sockfd(-1) 
        {}

        void initServer()
        {
            //1.创建socket
            _sockfd=socket(AF_INET,SOCK_DGRAM,0);//创建套接字
            if(_sockfd==-1)
            {
                cerr<<"socket error: "<<errno<<" : "<<strerror(errno)<<endl;
                exit(SOCKET_ERR);
            }
            cout<<"socket success: "<<" : "<<_sockfd<<endl;
            //2.绑定port , ip
            struct sockaddr_in local;
            bzero(&local,sizeof(local));
            local.sin_family=AF_INET;
            local.sin_port=htons(_port);
            local.sin_addr.s_addr=inet_addr(_ip.c_str());
            //local.sin_addr.s_addr=htonl(INADDR_ANY);//任意地址bind，服务器的真实写法
            int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
            if(n==-1)
            {
                cerr<<"bind error: "<<errno<<" : "<<strerror(errno)<<endl;
                exit(BIND_ERR);
            }
        }

        void start()
        {
            //服务器的本质就是死循环 
            char buffer[gnum];
            for(;;)
            {
                //读取数据
                struct sockaddr_in peer;
                socklen_t len= sizeof(peer);
                size_t s= recvfrom(_sockfd,buffer,sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);
                //1.数据是什么  2.谁发的
                if(s > 0)
                {
                    string clientip = inet_ntoa(peer.sin_addr);//1.网络序列 2.int->点分十进制ip
                    uint16_t clientport = ntohs(peer.sin_port);
                    string message = buffer;

                    cout<<clientip<<"["<<clientport<<"]#"<<message<<endl;

                    _callback(_sockfd,clientip,clientport,message);
                }
            }
        }

        ~udpServer()
        {}

    private:
        uint16_t _port;//服务器需要绑定的端口号
        string _ip;//实际上一款网络服务器，不建议指明一个ip
        int _sockfd;
        func_t _callback;
    };
}
